package mdt.action;

import org.tigris.gef.base.Editor;
import org.tigris.gef.base.Globals;
import org.tigris.gef.base.GuideGrid;
import org.tigris.gef.base.SelectionManager;
import org.tigris.gef.presentation.Fig;
import org.tigris.gef.presentation.FigEdge;
import org.tigris.gef.presentation.FigNode;
import org.tigris.gef.util.VetoableChangeEventSource;
import mdt.program.MDTGraphModel;
import mdt.figure.FigMDT;
import mdt.model.IEdgeModel;
import mdt.model.INodeModel;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.beans.VetoableChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

/**
 * Created by xiaobyu on 6/23/2016.
 */
public class PasteAction extends AbstractAction {
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(PasteAction.class.getName());

    public PasteAction() {
        super("Paste");
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        SelectionManager sm = Globals.curEditor().getSelectionManager();
        List<Fig> total = Globals.clipBoard;
        List<FigNode> nodesToCopy = new ArrayList<>();
        List<FigEdge> edgesToLocalCopy = new ArrayList<>();
        List<FigEdge> edgesToRemoteCopy = new ArrayList<>();
        List<FigEdge> edgesIgnored = new ArrayList<>();
        List<Fig> othersToCopy = new ArrayList<>();

        for (Fig f : total) {
            if (f instanceof FigNode) {
                nodesToCopy.add((FigNode)f);
            } else if (f instanceof FigEdge) {
                FigNode srcNode = ((FigEdge) f).getSourceFigNode();
                FigNode dstNode = ((FigEdge) f).getDestFigNode();
                if (total.contains(srcNode) && total.contains(dstNode)) {
                    edgesToRemoteCopy.add((FigEdge) f);
                } else if (!total.contains(srcNode) && !total.contains(dstNode)) {
                    edgesToLocalCopy.add((FigEdge) f);
                } else {
                    edgesIgnored.add((FigEdge) f);
                }
            } else {
                othersToCopy.add(f);
            }
        }

        if (nodesToCopy.size() > 0 && edgesToLocalCopy.size() > 0) {
            LOG.warning("Local copy of edges are ignored when shapeNode figures are also selected: " + edgesToLocalCopy);
            edgesIgnored.addAll(edgesToLocalCopy);
        }
        if (edgesIgnored.size() > 0) {
            LOG.warning("Following edges will not be copied: " + edgesIgnored);
        }

        Editor ce = Globals.curEditor();
        int gridSze = ((GuideGrid) ce.getGuide()).gridSize();
        List<Fig> newFigs = new ArrayList<>();
        for (FigNode f : nodesToCopy) {
            f = (FigNode) f.clone();
            Object owner = f.getOwner();
            if (owner instanceof VetoableChangeEventSource
                    && f instanceof VetoableChangeListener)
                ((VetoableChangeEventSource) owner)
                        .addVetoableChangeListener((VetoableChangeListener) f);

            if (f instanceof FigMDT) {
                ((FigMDT)f).translateCloned(gridSze, gridSze);
            } else {
                f.translate(gridSze, gridSze);
            }

            for (FigEdge edge : f.getFigEdges()){ //invalid edges, copied from original FigNode
                f.removeFigEdge(edge);
            }

            ce.add(f);

            ((MDTGraphModel)ce.getGraphModel()).addClonedNode(f);
            newFigs.add(f);
        }

        for (FigEdge edge : edgesToLocalCopy) {
            //FigNode srcNode = edge.getSourceFigNode();
            //FigNode dstNode = edge.getDestFigNode();
            FigEdge cloned = (FigEdge)edge.clone();

            ((INodeModel)edge.getSourceFigNode().getOwner()).addSrcDependency((IEdgeModel)cloned.getOwner());
            ((INodeModel)edge.getDestFigNode().getOwner()).addDstDependency((IEdgeModel)cloned.getOwner());

            edge.getSourceFigNode().addFigEdge(cloned);
            edge.getDestFigNode().addFigEdge(cloned);
            if (cloned instanceof FigMDT) {
                ((FigMDT)cloned).translateCloned(gridSze, gridSze);
            } else {
                cloned.translate(gridSze, gridSze);
            }
            ce.add(cloned);
            ((MDTGraphModel)ce.getGraphModel()).addClonedEdge(edge);
            newFigs.add(cloned);
        }

        sm.deselectAll();
        sm.select(newFigs);
    }
}
